#include "evaluation.h"

namespace IAlib
{

Evaluation::Evaluation()
{
}

QList<ItsAction*> Evaluation::proceduresToItsActions(const QList<Procedure*> list)
{
    QList<ItsAction*> actions;
    for (int i = 0; i < list.size(); i++)
    {
        actions.append(list[i]->getActions());
    }
    return actions;
}

int Evaluation::getSequenceEfficiency( const int index) const
{
    if (m_sequence_efficiency.contains(index))
    {
        return m_sequence_efficiency[index];
    }
    else
    {
        return 0;
    }
}

int calculateEfficiency(const QList<Procedure*>& list)
{
    int efficiency = 0;
    for ( int i = 0; i < list.size(); i++)
    {
        efficiency = efficiency + list[i]->getEfficiency();
    }
    return  efficiency;
}

int Evaluation::intersection_number(const int index) const
{
    int intersection = 0;
    for (int i = 0; i < m_all_possible_sequences[index].size(); i++)
    {
        for (int j = 0; j < m_learner_actions.size(); j++)
        {
            if (m_similarity_matrix[index][i][j])
            {
                intersection++;
            }
        }
    }
    return intersection;
}

void Evaluation::exeEvaluation(const QList<ItsAction *> learner_actions)
{
    m_learner_actions = learner_actions;
    int * indexs = new int[m_sorted_missions.size()];
    for ( int n = 0; n < m_sorted_missions.size(); n++) indexs[n] = 0;

    int nb_sequence = 0;
    int max_sequence = 1;
    for (int i = 0; i < m_sorted_missions.size(); i++)
    {
        max_sequence = max_sequence * m_sorted_missions[i]->getProcedures().size();
    }

    QList<QList<Procedure*> > temp_list;
    while (nb_sequence < max_sequence)
    {
        for (int i = 0; i < m_sorted_missions.size();i++)
        {
            indexs[i] = qrand() % m_sorted_missions[i]->getProcedures().size();
        }
        QList<Procedure*> sequence;
        for (int i = 0; i < m_sorted_missions.size();i++)
        {
            sequence.append(m_sorted_missions[i]->getProcedures()[indexs[i]]);
        }
        if (!temp_list.contains(sequence))
        {
            temp_list.append(sequence);
            nb_sequence++;
        }
    }

    while (temp_list.size() > 1)
    {
        int index_max = 0;
        for (int i = 1; i < temp_list.size(); i++)
        {
            if ( calculateEfficiency(temp_list[i]) > calculateEfficiency(temp_list[index_max]))
            {
                index_max = i;
            }
        }
        m_all_possible_sequences.append(temp_list[index_max]);
        temp_list.removeAt(index_max);
    }
    m_all_possible_sequences.append(temp_list[0]);

    for (int i = 0; i < m_all_possible_sequences.size(); i++)
    {
        int sequence_efficiency = 0;
        for (int j = 0; j < m_all_possible_sequences[i].size(); j++)
        {
            sequence_efficiency = sequence_efficiency + m_all_possible_sequences[i][j]->getEfficiency();
            //qDebug()<<m_all_possible_sequences[i][j]->getName();
        }
        m_sequence_efficiency.insert(i, sequence_efficiency);
        //qDebug()<<"--------------------------------------------------";

    }

    for (int i = 0; i < m_sorted_missions.size(); i++)
    {
        if (m_sorted_missions[i]->getBestProcedure() != NULL)
        {
            m_optimal_sequence.append(m_sorted_missions[i]->getBestProcedure());
        }
    }

    for (int i = 0; i <  m_all_possible_sequences.size(); i++)
    {
        bool **similarity_matrix;
        QList<ItsAction*> actions = proceduresToItsActions(m_all_possible_sequences[i]);
        similarity_matrix = new bool*[actions.size()];
        for (int i = 0; i < actions.size() ; i++)
        {
            similarity_matrix[i] = new bool[learner_actions.size()];
        }
        for (int i = 0; i < actions.size(); i++)
        {
            for ( int j = 0; j < learner_actions.size(); j++)
            {
                if (actions[i]->equal(*learner_actions[j]))
                {
                    similarity_matrix[i][j] = true;
                }
                else
                {
                    similarity_matrix[i][j] = false;
                }
            }
        }
        m_similarity_matrix.append(similarity_matrix);
    }

    for (int i = 0; i < m_all_possible_sequences.size(); i++)
    {
        int efficiency = 0;
        for (int j = 0; j < m_all_possible_sequences[i].size(); j++)
        {
            efficiency = efficiency + m_all_possible_sequences[i][j]->getEfficiency();
        }
        m_sequence_efficiency.insert(i, efficiency);
    }

    int max_intersection_number = 0;
    for (int i = 0; i < m_similarity_matrix.size(); i++)
    {
        int intersection = intersection_number(i);
        if (intersection > max_intersection_number)
        {
            max_intersection_number = intersection;
        }
    }
    for (int i = 0; i < m_similarity_matrix.size(); i++)
    {
        int intersection = intersection_number(i);
        if (intersection == max_intersection_number)
        {
            m_most_similar_sequence.append(i);
        }
    }
}

bool Evaluation::orderObserved(const QList<ItsAction *> &sequence, const QList<ItsAction *> &learner)
{
    for (int i = 0; i < sequence.size(); i++)
    {
        for ( int j = 0; j < learner.size(); j++)
        {
            if (sequence[i]->equal(*learner[j]) && i > 0)
            {
                for (int n = i - 1; n >= 0; n-- )
                {
                    for ( int m = j + 1; m < learner.size(); m++)
                    {
                        if (sequence[n]->equal(*learner[m]))
                        {
                            return false;
                        }
                    }
                }
            }

        }
    }
    return true;
}

int Evaluation::getBestProcedure(const Mission& mission)
{
	int index = -1;
	int max_efficiency = 0;
	QList<Procedure*> list = mission.getProcedures();
	for (int i = 0; i < list.size(); i++)
	{
		if (list[i]->getEfficiency() > max_efficiency)
		{
			max_efficiency = list[i]->getEfficiency();
			index = i;
		}
	}
	return index;
}

}
